package com.fiume.travel.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.fiume.travel.interceptor.PrimaryKeyInterceptor;
import com.github.pagehelper.PageInterceptor;
import org.apache.ibatis.logging.log4j2.Log4j2Impl;
import org.apache.ibatis.plugin.Interceptor;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.util.Properties;

/**
 * <p>
 * Description: 声明mybatis的配置
 * </p>
 *
 * @author fiume
 * @version v1.0.0
 * @create 2021-02-12 22:25
 * @see com.fiume.travel.config
 */
// 声明配置类
@Configuration
// 将自定义的数据库相关配置文件导入,比如用户名,密码等等
@PropertySource(value = "classpath:db.properties")
@MapperScan(
        basePackages =
                {
                        "com.fiume.travel.mapper", //代码生成器相关sql--单表
                        "com.fiume.travel.mapperExt" // 手动编写的sql(部分复杂sql使用代码生成器无法生成或者规则较为复杂,使用手写的更加方便)--多表
                },
        sqlSessionFactoryRef = "sqlSessionFactoryBean" //Ref:关联,引用 指定使用sqlSessionFactoryBean创建上方扫描到的包下的接口的实现类
)
public class MybatisConfig {

    @Value("${dataSource.username}")
    private String username;

    @Value("${dataSource.password}")
    private String password;

    @Value("${dataSource.driverClassName}")
    private String driverClassName;

    @Value("${dataSource.url}")
    private String url;

    // 雪花算法 机器唯一id
    @Value("${seq.workerId}")
    private String workerId;

    // 雪花算法 数据中心唯一id
    @Value("${seq.datacenterId}")
    private String datacenterId;

    /**
     * 数据源配置,若未指定名称,默认使用当前方法名为bean的名称,此处指定名称,便于后续管理
     */
    @Bean("druidDataSource")
    public DruidDataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    /**
     * 事务管理
     */
    @Bean("transactionManager")
    public DataSourceTransactionManager transactionManager(@Qualifier("druidDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    /**
     * sqlSession工厂(sql会话工厂,sql会话管理)
     */
    @Bean("sqlSessionFactoryBean")
    public SqlSessionFactoryBean sqlSessionFactoryBean(@Qualifier("druidDataSource") DataSource dataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        //指定数据源
        sqlSessionFactoryBean.setDataSource(dataSource);
        //别名映射,将数据库字段与pojo文件夹下的类一一对应
        sqlSessionFactoryBean.setTypeAliasesPackage("com.fiume.travel.pojo");

        //设置mybatis的高级配置,比如驼峰映射,日志,缓存等 全限定名的原因是与注解@Configuration重名了
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setLogImpl(Log4j2Impl.class);
        sqlSessionFactoryBean.setConfiguration(configuration);
        //调用分页拦截器,拦截查询请求,完成分页查询
        sqlSessionFactoryBean.setPlugins(new Interceptor[]{
                //此处配置了拦截多个插件的拦截方式,但此处暂时只有一个分页插件
                initPageInterceptor(),
                initPrimaryKeyInterceptor()
        });
        return sqlSessionFactoryBean;
    }

    /**
     * 创建雪花算法工具对象
     */
    @Bean
    public SnowflakeIdWorker snowflakeIdWorker(){
        return new SnowflakeIdWorker(Long.valueOf(workerId),Long.valueOf(datacenterId));
    }

    /**
     * 创建主键拦截器对象
     */
    @Bean
    public PrimaryKeyInterceptor initPrimaryKeyInterceptor(){
        PrimaryKeyInterceptor primaryKeyInterceptor =  new PrimaryKeyInterceptor();
        // 指定主键的名称
        Properties properties = new Properties();
        properties.setProperty("primaryKey", "id");
        primaryKeyInterceptor.setProperties(properties);
        primaryKeyInterceptor.setSnowflakeIdWorker(snowflakeIdWorker());
        return primaryKeyInterceptor;
    }

    /**
     * 创建分页插件类,并将之存放到IOC容器中
     */
    @Bean
    public PageInterceptor initPageInterceptor(){
        //1. 创建分页拦截器对象
        PageInterceptor pageInterceptor = new PageInterceptor();
        //2. 设置分页拦截器属性
        //2.1 分页拦截器需要properties类型的数据进行设置
        Properties properties = new Properties();
        //2.2 设置分页拦截器相关配置
        //设置数据库方言
        properties.setProperty("helperDialect", "mysql");
        //该参数默认为false
        //设置为true时，可以根据每页显示条数和当前页页码进行分页查询
        properties.setProperty("offsetAsPageNum", "true");
        //分页查询是需要查询到总条数,如果此处不配置,则需要在每次请求时传入3个数据,即pageNum,pageSize和count(T/F)
        properties.setProperty("rowBoundsWithCount", "true");
        //3. 将配置导入
        pageInterceptor.setProperties(properties);
        return pageInterceptor;
    }
}
